新版Spring Security6.2案例

您所在的位置:网站首页 adobe代理身份验证 用户名和密码是什么 新版Spring Security6.2案例

新版Spring Security6.2案例

2024-07-14 21:23| 来源: 网络整理| 查看: 265

前言:

前面有翻译了新版Spring Security6.2架构,包括总体架构,Authentication和Authorization,感兴趣可以直接点链接,这篇翻译官网给出的关于Authentication的Username/Password这页。

首先呢,官网就直接给出了基于用户名和密码的认证的代码,可以说是spring security的一个入门小案例,表单登录,输入用户名密码,和内存中的用户名密码匹配,如果匹配了就会成功登录。

Username/Password Authentication

验证用户的最常用方法之一是验证用户名和密码。Spring Security为使用用户名和密码进行身份验证提供了全面的支持。可以通过以下方式配置用户名密码认证

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) .formLogin(Customizer.withDefaults()); return http.build(); } @Bean public UserDetailsService userDetailsService() { UserDetails userDetails = User.withDefaultPasswordEncoder() .username("user") .password("password") .roles("USER") .build(); return new InMemoryUserDetailsManager(userDetails); } }

前面的配置会自动向 SecurityFilterChain 注册内存中 UserDetailsService,将DaoAuthenticationProvider 注册到默认的 AuthenticationManager,并启用表单登录和 HTTP 基本身份验证。

官网这边也列举了很多例子,我这边也都附上了超链接,因为前面代码是表单登录的,所以优先把超链接第一点,"我想了解表单登录如何工作"这节翻译了。

要了解更多关于usernamepassword身份验证的信息,请考虑以下用例:

我想了解表单登录如何工作我想了解HTTP基本身份验证如何工作我想了解DaoAuthenticationProvider如何工作我想在内存中管理用户我想管理数据库中的用户我想在LDAP中管理用户我想发布一个用于自定义身份验证的AuthenticationManager bean我想自定义全局AuthenticationManager 表单登录的原理

Spring Security支持通过HTML表单提供用户名和密码。首先,我们看看如何将用户重定向到登录表单

上图基于 SecurityFilterChain 流程图。 

首先,用户向未授权的资源 (/private) 发出未经身份验证的请求。Spring Security 的 AuthorizationFilter 通过抛出 AccessDeniedException 来指示未经身份验证的请求被拒绝。由于用户未经过身份验证,因此 ExceptionTranslationFilter 将启动“启动身份验证”,并使用配置的 AuthenticationEntryPoint 将重定向发送到登录页。在大多数情况下,AuthenticationEntryPoint 是 LoginUrlAuthenticationEntryPoint 的实例。浏览器请求重定向到的登录页面。应用程序中的某些内容必须呈现在登录页面。

当提交用户名和密码时,UsernamePasswordAuthenticationFilter对用户名和密码进行认证。UsernamePasswordAuthenticationFilter扩展了AbstractAuthenticationProcessingFilter,因此下面的图看起来应该非常相似。

该图建立在SecurityFilterChain图的基础上。

1.当用户提交其用户名和密码时,UsernamePasswordAuthenticationFilter 通过从 HttpServletRequest 实例中提取用户名和密码来创建 UsernamePasswordAuthenticationToken,UsernamePasswordAuthenticationToken是一种身份验证类型。

2.接下来,将UsernamePasswordAuthenticationToken传递到要进行身份验证的AuthenticationManager实例中。AuthenticationManager的细节取决于用户信息的存储方式。

3.如果身份验证失败,则定义为”失败“,并做如下:

        (1).清除SecurityContextHolder。

        (2).调用 RememberMeServices.loginFail。如果未配置“记住我”,则为空操作。请参阅 Javadoc 中的 RememberMeServices 接口。

        (3).调用AuthenticationFailureHandler。请参阅Javadoc中的AuthenticationFailureHandler类

4.如果身份验证成功,则显定义为”成功“,并做如下:

        (1).SessionAuthenticationStrategy收到新登录的通知。请参阅Javadoc中的SessionAuthenticationStrategy接口。

        (2).身份验证设置在securitycontexholder上。请参阅Javadoc中的SecurityContextPersistenceFilter类。

        (3).RememberMeServices。调用loginSuccess。如果记得我没有配置,这是一个no-op。请参阅Javadoc中的memormeservices接口。

        (4).ApplicationEventPublisher发布一个InteractiveAuthenticationSuccessEvent事件。

        (5).调用AuthenticationSuccessHandler。通常,这是一个SimpleUrlAuthenticationSuccessHandler,当我们重定向到登录页面时,它会重定向到由ExceptionTranslationFilter保存的请求。

默认情况下,Spring Security 表单登录处于启用状态。但是,一旦提供了任何基于 servlet 的配置,就必须显式提供基于表单的登录。以下示例显示了一个最小的显式 Java 配置:

public SecurityFilterChain filterChain(HttpSecurity http) { http .formLogin(withDefaults()); // ... }

在前面的配置中,Spring Security 呈现默认登录页面。大多数生产应用程序都需要自定义登录表单。

以下配置演示了如何提供自定义登录表单。

ublic SecurityFilterChain filterChain(HttpSecurity http) { http .formLogin(form -> form .loginPage("/login") .permitAll() ); // ... }

在 Spring Security 配置中指定登录页面时,用户负责呈现页面。以下 Thymeleaf 模板生成符合 /login 登录页的 HTML 登录表单。

Please Log In Please Log In Invalid username and password. You have been logged out.

关于默认 HTML 表单,有几个关键点:

表单应执行 post 到 /login。该表单需要包含一个 CSRF 令牌,该令牌由 Thymeleaf 自动包含。表单应在名为 username 的参数中指定用户名。表单应在名为 password 的参数中指定密码。如果找到名为 error 的 HTTP 参数,则表示用户未能提供有效的用户名或密码。如果找到名为 logout 的 HTTP 参数,则表示用户已成功注销。

许多用户只需要自定义登录页面即可。但是,如果需要,您可以使用其他配置自定义前面显示的所有内容。

如果您使用 Spring MVC,则需要一个将 GET /login 映射到我们创建的登录模板的控制器。以下示例显示了一个最小的 LoginController:

@Controller class LoginController { @GetMapping("/login") String login() { return "login"; } }

最后在官网Username/Password这页中,还有描写关于自定义身份的authentication bean和全局authenticationManger,也就是上面超链接最后2点,先翻译出来,再后续博客中接着讲,本文可以着重看前面的表单登录即可。

发布一个AuthenticationManager bean

一个相当常见的要求是发布 AuthenticationManager bean 以允许自定义身份验证,例如在 @Service 或 Spring MVC @Controller中。例如,您可能希望通过 REST API 而不是使用表单登录对用户进行身份验证。

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login").permitAll() .anyRequest().authenticated() ); return http.build(); } @Bean public AuthenticationManager authenticationManager( UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(userDetailsService); authenticationProvider.setPasswordEncoder(passwordEncoder); return new ProviderManager(authenticationProvider); } @Bean public UserDetailsService userDetailsService() { UserDetails userDetails = User.withDefaultPasswordEncoder() .username("user") .password("password") .roles("USER") .build(); return new InMemoryUserDetailsManager(userDetails); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }

有了上述配置,您就可以创建一个使用AuthenticationManager的@RestController,如下所示:

@RestController public class LoginController { private final AuthenticationManager authenticationManager; public LoginController(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @PostMapping("/login") public ResponseEntity login(@RequestBody LoginRequest loginRequest) { Authentication authenticationRequest = UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.username(), loginRequest.password()); Authentication authenticationResponse = this.authenticationManager.authenticate(authenticationRequest); // ... } public record LoginRequest(String username, String password) { } }

本例中,如果需要,您有责任将经过身份验证的用户保存在securitycontextrerepository中。例如,如果使用HttpSession在请求之间持久化SecurityContext,您可以使用httpessionsecuritycontextrepository。

自定义 AuthenticationManager

通常,Spring Security 在内部构建一个 AuthenticationManager,该管理器由 DaoAuthenticationProvider 组成,用于用户名/密码身份验证。在某些情况下,可能仍需要自定义 Spring Security 使用的 AuthenticationManager 实例。例如,您可能需要简单地为缓存用户禁用凭据擦除。您可以使用以下配置发布 AuthenticationManager:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login").permitAll() .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) .formLogin(Customizer.withDefaults()); return http.build(); } @Bean public AuthenticationManager authenticationManager( UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(userDetailsService); authenticationProvider.setPasswordEncoder(passwordEncoder); ProviderManager providerManager = new ProviderManager(authenticationProvider); providerManager.setEraseCredentialsAfterAuthentication(false); return providerManager; } @Bean public UserDetailsService userDetailsService() { UserDetails userDetails = User.withDefaultPasswordEncoder() .username("user") .password("password") .roles("USER") .build(); return new InMemoryUserDetailsManager(userDetails); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }

或者,您可以利用用于构建 Spring Security 的全局 AuthenticationManager 的 AuthenticationManagerBuilder 作为 Bean 发布的事实。您可以按如下方式配置构建器:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // ... return http.build(); } @Bean public UserDetailsService userDetailsService() { // Return a UserDetailsService that caches users // ... } @Autowired public void configure(AuthenticationManagerBuilder builder) { builder.eraseCredentials(false); } } 参考文献:

《spring boot官网》



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3